package com.mercury.core.util;

import com.mercury.core.exception.MercuryException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mercury
 * @date 2021/2/3 11:47 上午
 */
@Slf4j
public class ReflectUtils {
    /**
     * 根据属性名称获取对象属性值
     *
     * @param target    目标对象
     * @param fieldName 属性名称
     * @return
     */
    public static Object getFieldValue(Object target, String fieldName) {
        try {
            Field field = target.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(target);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("getFieldValue failed error:", e);
            throw new MercuryException(String.format("no such field : %s,", fieldName));
        }
    }

    /**
     * 获取所有属性值，不包括父类的属性
     *
     * @param target 目标对象
     * @return
     */
    public static List<String> getAllFields(Object target) {
        List<Field> fields = Arrays.asList(target.getClass().getDeclaredFields());
        if (CollectionUtils.isEmpty(fields)) {
            return null;
        }
        return fields.stream().map(Field::getName).collect(Collectors.toList());
    }

    /**
     * 通过反射设置对象属性值
     *
     * @param target            目标对象
     * @param fieldValueMapping 属性和值的键值对象
     */
    public static void setFieldValue(Object target, Map<String, Object> fieldValueMapping) {
        if (Objects.isNull(target)) {
            return;
        }
        if (Objects.isNull(fieldValueMapping)) {
            return;
        }
        Field[] fields = target.getClass().getDeclaredFields();
        for (Field ele : fields) {
            for (Map.Entry<String, Object> entry : fieldValueMapping.entrySet()) {
                String field = entry.getKey();
                Object value = entry.getValue();
                if (Objects.equals(ele.getName(), field) && Objects.nonNull(value)) {
                    ele.setAccessible(true);
                    try {
                        ele.set(target, value);
                    } catch (IllegalAccessException e) {
                        log.error("setFieldValue failed error:", e);
                        throw new MercuryException(String.format("reflect set value fail field:%s value:%s,", field, value));
                    }
                }
            }
        }
    }
}
